 <?php
using("Expression_Expression");
using("Expression_Exception");
using("Utils_Reflection_Facade");

define("EXPRESSION_EVALUATE", "evaluate");

/**
 * Operator which can be applied to multiple expressions
 *
 * <p>The default behavior for the operator is to concetenate the operator symbol
 * between each of the expressions.
 * 
 * @author Alexander Schearer <aas11@duke.edu>
 */
class Expression_Operator implements Expression_Expression {
	
	/**
	 * String representation of the given operator
	 *
	 * @var String
	 */
	private $_operator;
	
	/**
	 * String to be used to compile an expression
	 *
	 * @var String
	 */
	private $_result;
	
	/**
	 * An array of expressions which fall underneath this operator
	 *
	 * @var array
	 */
	protected $_children;
	
	public function __construct($operator, array $expressions) {
		$this->_operator = $operator;
		$this->_children = $expressions;
	}
	
	/**
	 * Add a new operand to the expression to be used when evaluated
	 *
	 * @param Expression_Expression $operand
	 * @return boolean whether the expression was added
	 */
	public function addOperand(Expression_Expression $operand) {
		$this->_children[] = $operand;
		return true;
	}
	
	/**
	 * Return the evaluated operator as a string
	 * 
	 * @throws _Exception
	 *
	 * @return String
	 */
	public function evaluate() {
		$this->build($this->invokeLeaf(current($this->_children)));
		while (next($this->_children)) {
			$this->build($this->_operator);
			$this->build($this->invokeLeaf(current($this->_children)));
		}
		return $this->compile();
	}
	
	/**
	 * Convert the operator to a string
	 *
	 * @throws _Exception
	 * 
	 * @return String
	 */
	public function __toString() {
		return $this->evaluate();
	}
	
	/**
	 * Retrieve the string representation of the operator
	 *
	 * @return String
	 */
	protected function getOperator() {
		return $this->_operator;
	}
	
	/**
	 * Add a new element to the result text with a space separator
	 *
	 * @param String $text
	 */
	protected function build($text) {
		$this->_result .= " " . $text; 
	}
	
	/**
	 * Retrieve the result text
	 *
	 * @return String
	 */
	protected function compile() {
		return trim($this->_result);
	}
	
	/**
	 * Invoke the evaluate method on the given leaf
	 *
	 * @throws _Exception
	 * 
	 * @param Expression_Expression $$child
	 */
	protected function invokeLeaf(Expression_Expression $child) {
		try {
			return Utils_Reflection_Facade::invokeArgs($child, EXPRESSION_EVALUATE, array());
		} catch (Utils_Reflection_Exception $e) {
			throw new Builder_Exception($e);
		}
	}
}
?>